package com.wuxinwudai.android.util;

import android.content.Context;
import android.os.Environment;
import android.os.StatFs;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * FileUtil 类为文件操作工具类
 * @author 嘉庆
 *
 */
public class FileUtils {
	
	/**
	 * 文件扩展名分割符
	 */
	 public final static String FILE_EXTENSION_SEPARATOR = ".";
    private final static DecimalFormat df = new DecimalFormat("0.00");


    /**
     * 从文件读取字节流
     * @param file 文件
     * @return 读取是否成功
     * @throws Exception
     */
	 public static byte[] readFile(File file) throws Exception{
         return StreamUtils.toBytes(new FileInputStream(file));
     }
	/**
	 * 从文件中读取字符串
	 * @param filePath 文件名
	 * @param charsetName 字符串编码
	 * @return 文本内容
	 */
    public static StringBuilder readFile(String filePath, String charsetName) {
        File file = new File(filePath);
        StringBuilder fileContent = new StringBuilder("");
        if (file == null || !file.isFile()) {
            return null;
        }
        BufferedReader reader = null;
        try {
            InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);
            reader = new BufferedReader(is);
            String line = null;
            while ((line = reader.readLine()) != null) {
                if (!fileContent.toString().equals("")) {
                    fileContent.append("\r\n");
                }
                fileContent.append(line);
            }
            reader.close();
            return fileContent;
        } catch (IOException e) {
            throw new RuntimeException("IOException occurred. ", e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException("IOException occurred. ", e);
                }
            }
        }
    }

    /**
     * 读取文件
     * @param context 上下文对象
     * @param filePath 文件路径
     * @return 读取的内容
     * @throws Exception
     */
    public static String readFile(Context context,String filePath) throws Exception{
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        FileInputStream fis = context.openFileInput(filePath);
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = fis.read(buffer)) != -1) {
            baos.write(buffer, 0, len);
        }
        String content = baos.toString();
        fis.close();
        baos.close();
        return content;
    }

    //region 写入文件
    /**
     * 将文件保存为字节流
     * @param file  将文件写入字节流
     * @return 字节流
     */
    public static byte[] writeFile(File file) {
        FileOutputStream outStream;
        try {
            outStream = new FileOutputStream(file);
            byte[] data = new byte[(int)file.length()];
            outStream.write(data);
            outStream.close();
            return data;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 将内容写入文件
     * @param filePath 文件路径
     * @param content 要写入文件的内容
     * @param append 是否在原文件内容后追加内容
     * @return
     */
    public static boolean writeFile(String filePath, String content, boolean append) {
        if (StringUtils.isNullOrWhiteSpace(content)) {
            return false;
        }
        FileWriter fileWriter = null;
        try {
            makeDir(filePath);
            fileWriter = new FileWriter(filePath, append);
            fileWriter.write(content);
            fileWriter.close();
            return true;
        } catch (IOException e) {
            throw new RuntimeException("IOException occurred. ", e);
        } finally {
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    throw new RuntimeException("IOException occurred. ", e);
                }
            }
        }
    }
    /**
     * 将文本内容写入文件中
     * @param filePath
     * @param contentList
     * @param append
     * @return
     */
    public static boolean writeFile(String filePath, List<String> contentList, boolean append) {
        if (ListUtils.isEmpty(contentList)) {
            return false;
        }

        FileWriter fileWriter = null;
        try {
            makeDir(filePath);
            fileWriter = new FileWriter(filePath, append);
            int i = 0;
            for (String line : contentList) {
                if (i++ > 0) {
                    fileWriter.write("\r\n");
                }
                fileWriter.write(line);
            }
            fileWriter.close();
            return true;
        } catch (IOException e) {
            throw new RuntimeException("IOException occurred. ", e);
        } finally {
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                    fileWriter = null;
                } catch (IOException e) {
                    throw new RuntimeException("IOException occurred. ", e);
                }
            }
        }
    }
    /**
     * 以新建文件方式写入文件
     * @param filePath
     * @param content
     * @return
     */
    public static boolean writeFile(String filePath, String content) {
        return writeFile(filePath, content, false);
    }
    /**
     * 以新建文件方式写入文件
     * @param filePath
     * @param contentList
     * @return
     */
    public static boolean writeFile(String filePath, List<String> contentList) {
        return writeFile(filePath, contentList, false);
    }
    /**
     * 以新建方式写入文件
     * @param filePath 文件路径
     * @param stream 输入流
     * @return 写入是否成功
     */
    public static boolean writeFile(String filePath, InputStream stream) {
        return writeFile(filePath, stream, false);
    }
    /**
     * 将流写入文件
     * @param filePath 文件路径
     * @param stream 输入流
     * @param append 是否追加
     * @return 写入是否成功
     */
    public static boolean writeFile(String filePath, InputStream stream, boolean append) {
        return writeFile(filePath != null ? new File(filePath) : null, stream, append);
    }
    /**
     * 以新建方式写入文件
     * @param file 写入文件
     * @param stream 输入流
     * @return 写入是否成功
     */
    public static boolean writeFile(File file, InputStream stream) {
        return writeFile(file, stream, false);
    }
    /**
     * 将输入流写入文件
     * @param file 文件对象
     * @param stream 输入流
     * @param append 是否追加到文件尾部
     * @return 写入是否成功
     */
    public static boolean writeFile(File file, InputStream stream, boolean append) {
        OutputStream o = null;
        try {
            makeDir(file.getAbsolutePath());
            o = new FileOutputStream(file, append);
            byte data[] = new byte[1024];
            int length = -1;
            while ((length = stream.read(data)) != -1) {
                o.write(data, 0, length);
            }
            o.flush();
            return true;
        } catch (FileNotFoundException e) {
            throw new RuntimeException("FileNotFoundException occurred. ", e);
        } catch (IOException e) {
            throw new RuntimeException("IOException occurred. ", e);
        } finally {
            if (o != null) {
                try {
                    o.close();
                    stream.close();
                } catch (IOException e) {
                    throw new RuntimeException("IOException occurred. ", e);
                }
            }
        }
    }
    /**
     * 保存文件内容
     * @param context 上下文对象
     * @param filePath 文件路径
     * @param content 写入内容
     * @param mode 写入模式
     * @throws Exception
     */
    public static void writeFile(Context context,String filePath,String content,int mode) throws Exception{
        FileOutputStream fos = context.openFileOutput(filePath,mode);
        fos.write(content.getBytes());
        fos.close();
    }
    //endregion

    /**
     * 文件拷贝
     * @param sourceFilePath 源文件路径
     * @param destFilePath 目标文件路径
     * @return 复制是否成功
     */
    public static boolean copyFile(String sourceFilePath, String destFilePath) {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(sourceFilePath);
        } catch (FileNotFoundException e) {
            throw new RuntimeException("FileNotFoundException occurred. ", e);
        }
        return writeFile(destFilePath, inputStream);
    }
    /**
     * 将文件读取到字符串列表
     * @param filePath 文件路径
     * @param charsetName 字符串编码
     * @return 读取文件行
     */
    public static List<String> readFileToList(String filePath, String charsetName) {
        File file = new File(filePath);
        List<String> fileContent = new ArrayList<String>();
        if (file == null || !file.isFile()) {
            return null;
        }

        BufferedReader reader = null;
        try {
            InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);
            reader = new BufferedReader(is);
            String line = null;
            while ((line = reader.readLine()) != null) {
                fileContent.add(line);
            }
            reader.close();
            return fileContent;
        } catch (IOException e) {
            throw new RuntimeException("IOException occurred. ", e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException("IOException occurred. ", e);
                }
            }
        }
    }
    
    /**
     * 获取不含文件扩展名的文件名
     * @param filePath 文件路径
     * @return 文件名
     */
    public static String getFileNameWithoutExtension(String filePath) {
        if (StringUtils.isNullOrWhiteSpace(filePath)) {
            return filePath;
        }
        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);
        int filePosi = filePath.lastIndexOf(File.separator);
        if (filePosi == -1) {
            return (extenPosi == -1 ? filePath : filePath.substring(0, extenPosi));
        }
        if (extenPosi == -1) {
            return filePath.substring(filePosi + 1);
        }
        return (filePosi < extenPosi ? filePath.substring(filePosi + 1, extenPosi) : filePath.substring(filePosi + 1));
    }
    
    /**
     * 获取文件的文件名
     * @param filePath 文件路径
     * @return 文件名
     */
    public static String getFileName(String filePath) {
        if (StringUtils.isNullOrWhiteSpace(filePath)) {
            return filePath;
        }
        int filePosi = filePath.lastIndexOf(File.separator);
        return (filePosi == -1) ? filePath : filePath.substring(filePosi + 1);
    }
    
    /**
     * 获取文件所在的文件夹
     * @param filePath 文件路径
     * @return 获取文件所在的文件夹路径，否则返回空串 
     */
    public static String getFolderName(String filePath) {
        if (StringUtils.isNullOrEmpty(filePath)) {
            return filePath;
        }
        int filePosi = filePath.lastIndexOf(File.separator);
        return (filePosi == -1) ? "" : filePath.substring(0, filePosi);
    }
    
    /**
     * 获取文件扩展名
     * @param filePath 文件路径
     * @return 文件扩展名或空串
     */
    public static String getFileExtension(String filePath) {
        if (StringUtils.isNullOrWhiteSpace(filePath)) {
            return filePath;
        }
        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);
        int filePosi = filePath.lastIndexOf(File.separator);
        if (extenPosi == -1) {
            return "";
        }
        return (filePosi >= extenPosi) ? "" : filePath.substring(extenPosi + 1);
    }

    //region 创建操作
    /**
     * 创建文件所在的文件夹
     * @param filePath 文件路径
     * @return 文件夹创建是否成功
     */
    public static boolean makeDir(String filePath) {
        String folderName = getFolderName(filePath);
        if (StringUtils.isNullOrWhiteSpace(folderName)) {
            return false;
        }
        File folder = new File(folderName);
        return (folder.exists() && folder.isDirectory()) ||  folder.mkdirs();
    }
    /**
     * 在 APP 目录下创建文件夹
     * @param dir 文件目录
     * @return 创建是否成功
     */
    public static boolean makeDirForApp(String dir){
        if (!StringUtils.isNullOrWhiteSpace(dir)){
            File file = new File(getRootFilePath() + dir);
            return file.mkdir();
        }
        return false;
    }
    //endregion


    /**
     * 判断指定文件是否存在
     * @param filePath 文件路径
     * @return
     */
    public static boolean fileExist(String filePath) {
        if (StringUtils.isNullOrWhiteSpace(filePath)) {
            return false;
        }
        File file = new File(filePath);
        return (file.exists() && file.isFile());
    }
    /**
     * 判断指定文件夹是否存在
     * @param foldPath 文件夹路径
     * @return 文件夹是否存在
     */
    public static boolean folderExist(String foldPath) {
        if (StringUtils.isNullOrWhiteSpace(foldPath)) {
            return false;
        }

        File dire = new File(foldPath);
        return (dire.exists() && dire.isDirectory());
    }
    //region 删除操作
    /**
     * 删除指定路径下的文件或文件夹
     * @param path 文件或文件夹路径
     * @return 删除是否成功
     */
    public static boolean deleteFile(String path) {
        if (StringUtils.isNullOrWhiteSpace(path)) {
            return true;
        }
        File file = new File(path);
        if (!file.exists()) {
            return true;
        }
        if (file.isFile()) {
            return file.delete();
        }
        if (!file.isDirectory()) {
            return false;
        }
        for (File f : file.listFiles()) {
            if (f.isFile()) {
                f.delete();
            } else if (f.isDirectory()) {
                deleteFile(f.getAbsolutePath());
            }
        }
        return file.delete();
    }
    /**
     * 删除最后修改时间在 lastUpdateTime 之前的目录和文件，并返回删除的文件数量
     *
     * @param dir     目录
     * @param lastUpdateTime 当前系统时间
     */
    public static int deleteDir(File dir, long lastUpdateTime) {
        int deletedFiles = 0;
        if (dir != null && dir.isDirectory()) {
            try {
                for (File child : dir.listFiles()) {
                    if (child.isDirectory()) {
                        deletedFiles += deleteDir(child, lastUpdateTime);
                    }
                    if (child.lastModified() < lastUpdateTime) {
                        if (child.delete()) {
                            deletedFiles++;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return deletedFiles;
    }

    /**
     * 删除指定文件夹内的文件
     * @param dir
     * @return
     */
    public static void deleteDir(File dir){
        if (dir!=null&&dir.exists()&&dir.isDirectory()){
            for (File item : dir.listFiles()){
                item.delete();
            }
        }
    }
    //endregion
    /**
     * 获取文件长度
     * @param path 文件路径
     * @return 获取文件长度，获取失败时返回 -1
     */
    public static long getFileSize(String path) {
        if (StringUtils.isNullOrWhiteSpace(path)) {
            return -1;
        }
        File file = new File(path);
        return (file.exists() && file.isFile() ? file.length() : -1);
    }
    /**
     * 将文件大小显示为格式化字符串
     * @param fileLength 文件长度
     * @return 文件大小
     */
    public static String formatFileLength(long fileLength){
        if (fileLength < 1024){
            return df.format((double)fileLength) + "B";
        }else if(fileLength < 1048576){
            return df.format((double)fileLength / 1024 ) + "KB";
        }else if(fileLength < 1073741824 ){
            return df.format((double)fileLength / 1048576) + "MB";
        }
        return df.format((double)fileLength / 1073741824) + "GB";
    }
    /**
     * 判断是否有 SD 卡
     * @return 是否有SD卡
     */
    public static boolean hasSDCard(){
        String status = Environment.getExternalStorageState();
        return status.equals(Environment.MEDIA_MOUNTED);
    }
    /**
     * 获取应用的根路径,以 / 结尾
     * @return 应用根路径
     */
    public static String getRootFilePath(){
        if (hasSDCard()){
            return Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator ;//路径：/sdcard/
        }
        return Environment.getDataDirectory().getAbsolutePath() + File.separator;//路径： /data/
    }
    /**
     * 获取可用的硬盘空间
     * @return 可用硬盘空间
     */
    public static long getFreeDiskSpace() {
        String status = Environment.getExternalStorageState();
        long freeSpace = 0;
        if (status.equals(Environment.MEDIA_MOUNTED)) {
            try {
                File path = Environment.getExternalStorageDirectory();
                StatFs stat = new StatFs(path.getPath());
                long blockSize = stat.getBlockSize();
                long availableBlocks = stat.getAvailableBlocks();
                freeSpace = availableBlocks * blockSize/1024;
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            return -1;
        }
        return (freeSpace);
    }
    /**
     * 获取文件夹大小
     * @param dir 获取文件夹大小
     * @return 文件夹大小
     */
    public static long getDirLength(File dir){
        if (dir == null) {
            return 0;
        }
        if (!dir.isDirectory()) {
            return 0;
        }
        long len = 0;
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                len += file.length();
            } else if (file.isDirectory()) {
                len += file.length();
                len += getDirLength(file); //递归
            }
        }
        return len;
    }
    /**
     * 获取由日期时间生成的临时文件名，不包含后缀
     * @return 临时文件名
     */
    public static String getTempFileName() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss_SS");
        String fileName = format.format(new Timestamp(System.currentTimeMillis()));
        return fileName;
    }

    /**
     * 获取以 MB 为单位的文件长度
     * @param fileLength 文件长度
     * @return 文件长度
     */
    public static String formatMB(long fileLength){
        return df.format((double)fileLength / 1048576) + "MB";
    }
    /**
     * 获取以 KB 为单位的文件长度
     * @param fileLength 文件长度
     * @return 文件长度
     */
    public static String formatKB(long fileLength){
        return df.format((double)fileLength / 1024) + "KB";
    }
    /**
     * 获取以 GB 为单位的文件长度
     * @param fileLength 文件长度
     * @return 文件长度
     */
    public static String formatGB(long fileLength){
        return df.format((double)fileLength / 1073741824) + "GB";
    }


}
